#pragma once
#include "Common.hpp"
#include "ThreadPool.hpp"
#include <sys/wait.h>

using namespace threadpool;
const static int maxlength = 8;

class TcpServer : public Nocopy
{
    using func_t = std::function<std::string(const std::string &)>;
    using task_t = std::function<void()>;

public:
    TcpServer(uint16_t port, func_t func)
        : _port(port), _func(func)
    {
    }
    void Init()
    {
        // 1.创建套接字
        _listen_fd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listen_fd < 0)
        {
            LOG(LogLevel::FATAL) << "socket error";
            exit(SOCKET_ERR);
        }
        LOG(LogLevel::INFO) << "socket success, listen fd: " << _listen_fd;

        // 2.绑定
        InetAddr addr(_port, "0");
        socklen_t len = sizeof(struct sockaddr_in);
        int n = bind(_listen_fd, CONV(addr.Peer()), len);
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind error";
            exit(BIND_ERR);
        }
        LOG(LogLevel::INFO) << "bind success, listen fd: " << _listen_fd;

        // 3.监听
        int ret = listen(_listen_fd, maxlength);
        if (ret < 0)
        {
            LOG(LogLevel::FATAL) << "listen error";
            exit(LISTEN_ERR);
        }
        LOG(LogLevel::INFO) << "listen success, listen fd: " << _listen_fd;
    }

    void Service(int sockfd, InetAddr addr)
    {
        // EchoServer
        while (true)
        {
            // n > 0, 读到n字节内容
            // n==0 , 写端关闭了
            // n<0 ,读取错误
            // 1.读取数据
            char buff[512];
            ssize_t n = read(sockfd, buff, sizeof(buff) - 1);
            if (n < 0)
            {
                LOG(LogLevel::WARNING) << "server read error";
                continue;
            }
            else if (n == 0)
            {
                LOG(LogLevel::INFO) << "client write exit, so server read exit";
                break;
            }

            buff[n] = 0;
            // std::string data = addr.AddrString() + " " + buff;
            std::string data = buff;
            LOG(LogLevel::INFO) << "have read: " << data;

            // 远程命令执行
            std::string message = _func(data);

            // // EchoServer
            // std::string message = "Server echo# ";
            // message += data;

            // 写回客户端
            n = write(sockfd, message.c_str(), message.size());
            if (n < 0)
            {
                LOG(LogLevel::WARNING) << "server write error";
                continue;
            }
        }
    }

    static void *Routine(void *data)
    {
        // 自己分离，不用主动回收
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(data);
        td->_tsvr->Service(td->_sockfd, td->_addr);
        return nullptr;
    }

    class ThreadData
    {
    public:
        ThreadData(int sockfd, const InetAddr &addr, TcpServer *tsvr)
            : _sockfd(sockfd), _addr(addr), _tsvr(tsvr)
        {
        }
        int _sockfd;
        InetAddr _addr;
        TcpServer *_tsvr;
    };

    void Run()
    {
        while (true)
        {
            // 4.获取连接
            struct sockaddr_in peer;
            socklen_t len = sizeof(struct sockaddr_in);
            int sockfd = accept(_listen_fd, CONV(&peer), &len);
            if (sockfd < 0)
            {
                LOG(LogLevel::FATAL) << "accept error";
                exit(ACCEPT_ERR);
            }
            InetAddr addr(peer);
            LOG(LogLevel::INFO) << "accept success, " << addr.AddrString();

            // 5.调用业务
            // version 0 --- 单进程版
            // Service(sockfd, addr);

            // version 2 --- 多线程版
            ThreadData td(sockfd, addr, this);
            pthread_t tid;
            pthread_create(&tid, nullptr, Routine, (void *)&td);

            // version 1 --- 多进程版
            // pid_t pid = fork();
            // if (pid < 0)
            // {
            //     LOG(LogLevel::FATAL) << "fork error";
            //     exit(FORK_ERR);
            // }
            // else if (pid == 0)
            // {
            //     // 关闭监听的文件描述符，不需要
            //     close(_listen_fd);
            //     if (fork() > 0)
            //         exit(0);
            //     Service(sockfd, addr);
            //     exit(0);
            // }
            // // 关闭连接的文件描述符，不做通信业务
            // close(sockfd);
            // waitpid(pid, nullptr, 0);

            // version 2 --- 多线程版
            // ThreadData td(sockfd, addr, this);
            // pthread_t tid;
            // pthread_create(&tid, nullptr, Routine, (void *)&td);

            // // version 3 --- 线程池版本
            // ThreadPool<task_t> *tp = ThreadPool<task_t>::GetInstance();
            // tp->EnQueue([sockfd, addr, this]()
            //             { this->Service(sockfd, addr); });
        }
    }

    ~TcpServer()
    {
    }

private:
    int _listen_fd;
    uint16_t _port;
    func_t _func;
};